
package pl.wroc.uni.ii.evolution.solutionspaces;

import java.util.Set;

import pl.wroc.uni.ii.evolution.engine.individuals.EvBinaryVectorIndividual;
import pl.wroc.uni.ii.evolution.engine.prototype.EvIndividual;
import pl.wroc.uni.ii.evolution.engine.prototype.EvObjectiveFunction;
import pl.wroc.uni.ii.evolution.engine.prototype.EvSolutionSpace;
import pl.wroc.uni.ii.evolution.utils.EvRandomizer;

/**
 * A solution space of EvBinaryVectorIndividual
 * 
 * @author Marek Chrusciel, Michal Humenczuk
 */
public class EvBinaryVectorSpace implements EvSolutionSpace<EvBinaryVectorIndividual> {

  private static final long serialVersionUID = 5496084423283990032L;

  private int dimension;

  private EvObjectiveFunction<EvBinaryVectorIndividual> objective_function;


  /**
   * Constructs binary string with dimension given in argument.
   * Objective function is set with <code>goal_function</code> argument
   * 
   * @param <code>goal_function</code> objective function for individual
   * @param <code>dimension</code> number of individuals chromosome dimension (length).
   */
  public EvBinaryVectorSpace(EvObjectiveFunction<EvBinaryVectorIndividual> goal_function, int dimension ) {
    this.dimension = dimension;

    setObjectiveFuntion(goal_function);
  }

  
  /**
   * @deprecated objective function must be first in the contructor, plz. use
   * the contructor with correct order
   */  
  public EvBinaryVectorSpace( int dimension, EvObjectiveFunction<EvBinaryVectorIndividual> goal_function ) {
    this.dimension = dimension;

    setObjectiveFuntion(goal_function);
  }  
  
  /**
   * Check if individual given with argument <code>individual</code> 
   * belongs to this solution space. True if individual is binary and has the same dimension.
   * 
   * @return if individual belongs to this solution space 
   * 
   */
  public boolean belongsTo( EvBinaryVectorIndividual individual ) {
    if ( individual == null ) {
      return false;
    }
    return individual.getDimension() == this.dimension;
  }

  /**
   * [not used in current version]
   * 
   * @return [nil]
   */
  public Set<EvSolutionSpace<EvBinaryVectorIndividual>> divide( int n ) {
    return null;
  }

  /**
   * [not used in current version]
   * 
   * @return [nil]
   */
  public Set<EvSolutionSpace<EvBinaryVectorIndividual>> divide( int n, Set<EvBinaryVectorIndividual> p ) {
    return null;
  }

  /**
   * Generates random BinaryIndividual.
   * 
   * @return new random binary individual
   */
  public EvBinaryVectorIndividual generateIndividual() {
    EvBinaryVectorIndividual individual = new EvBinaryVectorIndividual( dimension );
    int individual_size = individual.getDimension();
    for( int i = 0; i < individual_size; i++ ) {
      individual.vector[i]=Math.random() < 0.5;
    }
    individual.setObjectiveFunction( objective_function );
    return individual;
  }

  /** 
   * Gets dimension (length) of individuals chromosome 
   * 
   * @return dimension of individual
   */
  public int getDimension() {
    return dimension;
  }

  /**
   * If only individual is from correct class and dimension, return this
   * individual itself. In other case return null.
   * 
   * @return binary individual itself or null 
   */
  public EvBinaryVectorIndividual takeBackTo( EvBinaryVectorIndividual individual ) {
    if ( this.belongsTo( individual ) )
      return individual;
    else
      return null; 
  }

  /**
   * Generates individual with fixed probability of each bit.
   * 
   *  @return generated binary individual
   */
  public EvIndividual generateIndividual( double[] probability_vector ) {
    if ( probability_vector.length != dimension ) {
      throw new IllegalArgumentException(
          "Probability vector dimension must be equal to space dimension" );
    }

    EvBinaryVectorIndividual bin_individual = new EvBinaryVectorIndividual( dimension );
    for( int i = 0; i < dimension; i++ ) {
      bin_individual.vector[i] = EvRandomizer.INSTANCE.nextProbableBoolean( probability_vector[i] );
    }
    
    bin_individual.setObjectiveFunction(objective_function);
    
    return bin_individual;
  }

  /**
   * {@inheritDoc}
   */
  public void setObjectiveFuntion(EvObjectiveFunction<EvBinaryVectorIndividual> objective_function) {
    if (objective_function == null) {
      throw new IllegalArgumentException("Objective function cannot be null");
    }
    this.objective_function = objective_function;   
  }
 

  /**
   * {@inheritDoc}
   */  
  public EvObjectiveFunction<EvBinaryVectorIndividual> getObjectiveFuntion() {
    // TODO implement
    return objective_function;
  }
  
}
